package com.example.demo.heima.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * ******************************************************
 *
 * @author liugh9
 * @version 1.0
 * @classname NettyServer
 * @description
 * @date 2023/07/21 21:57
 * <p>
 * ******************************************************
 */
public class NettyServer {

    public static void main(String[] args) {
        NettyServer nettyServer = new NettyServer();
        nettyServer.start(8888);
    }

    private void start(int port) {
        // ServerSocketChannel产生的accept事件循环工作组
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        // SocketChannel产生的read/write事件循环工作组
        NioEventLoopGroup work = new NioEventLoopGroup();

        try {
            // 核心引导类
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        /**
                         * 客户端连接时初始化SocketChannel
                         * @param socketChannel
                         * @throws Exception
                         */
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            /**
                             * handler顺序
                             *
                             * 双向链表
                             * head -> out1 -> in1 -> in2 -> tail
                             *
                             * inBoundHandler接收数据的顺序
                             * head -> in1 -> in2 -> tail
                             *
                             * outBoundHandler返回数据的顺序
                             * head <- out1 <- tail
                             */
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            // pipeline.addLast(new LoggingHandler(LogLevel.INFO));
                            // pipeline.addLast(new NettyServerInBoundHandler1());
                            // pipeline.addLast(new NettyServerInBoundHandler2());

                            // pipeline.addFirst(new NettyServerOutBoundHandler1());
                            //测试tcp stick or half pack
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(65535, 0, 4,0, 4));
                            pipeline.addLast(new TcpStickHalfHandler1());

                            pipeline.addFirst(new LengthFieldPrepender(4));

                        }
                    });
            // 绑定端口
            ChannelFuture future = bootstrap.bind(port).sync();
            // 监听端口关闭
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }


    }
}
